<fix>[zbs]: sync cow snapshot size in scheduled volume resource sync#4599
<fix>[zbs]: sync cow snapshot size in scheduled volume resource sync#4599ZStack-Robot wants to merge 1 commit into
Conversation
|
Warning
|
| Layer / File(s) | Summary |
|---|---|
统计与快照能力契约 header/src/main/java/org/zstack/header/storage/..., header/src/main/java/org/zstack/header/volume/... |
新增 StorageResourceStats、快照模式、卷类型字段及资源大小同步消息和回复;卷与快照统计类改为复用统一父类。 |
主存储消息处理接入 storage/src/main/java/org/zstack/storage/primary/..., plugin/{ceph,localstorage,nfsPrimaryStorage,sharedMountPointPrimaryStorage}/..., simulator/... |
各主存储处理器切换至资源大小同步消息和回复,并为数据卷与根卷设置 REDIRECT_ON_WRITE 能力。 |
控制器统计与快照映射 storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java, plugin/{expon,xinfini,zbs}/... |
批量统计接口返回统一资源统计结果;ZBS 额外查询并返回快照实际大小。 |
定时同步编排与缓存 storage/src/main/java/org/zstack/storage/volume/VolumeManagerImpl.java |
新增快照同步能力缓存,按主存储能力执行卷/快照大小同步,并刷新卷实际大小和缓存状态。 |
ZBS 与 Ceph 集成验证 test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/* |
新增批量卷快照统计、COW 快照大小同步、缓存裁剪及 Ceph 非快照同步场景测试。 |
Estimated code review effort: 4 (Complex) | ~60 minutes
Sequence Diagram(s)
sequenceDiagram
participant VolumeManagerImpl
participant PrimaryStorage
participant StorageController
participant VolumeDatabase
VolumeManagerImpl->>PrimaryStorage: 查询快照能力
PrimaryStorage-->>VolumeManagerImpl: 返回快照模式
VolumeManagerImpl->>StorageController: 查询卷和快照实际大小
StorageController-->>VolumeManagerImpl: 返回资源统计结果
VolumeManagerImpl->>VolumeDatabase: 更新快照及卷实际大小
Possibly related PRs
- MatheMatrix/zstack#4446:实现相同的 ZBS 定时资源同步、统一统计模型及 COW 快照大小刷新流程。
Suggested reviewers: pandawuu, majin1996
Poem
我是小兔,抱来新统计,
卷与快照,大小分明晰。
COW 轻跳缓存间,
Ceph 静守不乱添。
同步完成,萝卜甜!
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | 标题准确概括了 ZBS 调度的卷资源同步中补同步 COW 快照大小的主要变更。 |
| Description check | ✅ Passed | 描述准确覆盖了 COW 快照大小同步、消息重命名、batchStats 返回类型和测试验证等主要改动。 |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
✨ Finishing Touches
📝 Generate docstrings
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
sync/xiangheng.zhao/fix-zbs-snapshot-capacity-not-update@@3
Warning
There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
🔧 ast-grep (0.44.1)
plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java
ast-grep timed out on this file
plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java
ast-grep retry budget exhausted before isolating this batch
plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java
ast-grep retry budget exhausted before isolating this batch
- 3 others
Comment @coderabbitai help to get the list of available commands.
bfbdb25 to
663ad87
Compare
ZBS COPY_ON_WRITE snapshot actual size is maintained by the storage backend and may change after snapshot creation. The console reads snapshot size from VolumeSnapshotVO, but the scheduled active-volume size sync refreshed only volume actual size before, so snapshot capacity could stay stale in the database. During scheduled active-volume size sync, only primary storages whose snapshot mode is COPY_ON_WRITE attach snapshot install paths to the batch volume resource size sync request. The reply carries snapshot actual sizes so VolumeSnapshotVO.size can be refreshed together with volume actual size, without adding a manual snapshot size query flow for the console. Rename BatchSyncVolumeSizeOnPrimaryStorageMsg to BatchSyncVolumeResourceSizeOnPrimaryStorageMsg because the scheduled batch sync now covers volume resources and, for COW snapshot backends, snapshot resources. Keep SyncVolumeSize and single-volume stats as volume-only flows. Query snapshot capability by primary storage identity and volume type. PrimaryStorageInventory#getIdentity provides the cache identity: normal primary storages use type, and external primary storages override it with their identity, so VolumeManagerImpl does not depend on external storage VOs or external/non-external type checks. For NFS AskVolumeSnapshotCapabilityMsg, getVolume()==null is the new scheduled sync path and uses volumeType directly. getVolume()!=null no longer keeps the old format->hvType judgment: this commit intentionally removes the format-to-hypervisor-type check, keeps only the KVM behavior branch, and deletes the non-KVM branch that previously returned setSupport(false). NFS snapshot capability is therefore documented as KVM-only for this flow. Use StorageResourceStats as the batchStats return parent for VolumeStats and VolumeSnapshotStats. Batch stats accepts one installPaths collection; ZBS detects snapshot paths by @ and uses the volume-with-snapshot agent API only when COW snapshot size sync is required. Test: git diff --cached --check Test: mvn -pl header,storage -Dmaven.test.skip=true clean package Resolves: ZSTAC-67903 Change-Id: I0f4c2b8e3a9d167f5c0e2b6a1d9c8e7f3456abcd
663ad87 to
b71004a
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java (1)
2674-2698: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win三处
AskVolumeSnapshotCapabilityMsg处理逻辑重复,建议抽取公共方法。
LocalStorageBase、NfsPrimaryStorage、SMPPrimaryStorageBase中新增的 volumeType 回退与 Data/Root/Memory 分支设置 arrangement/placement/mode 的逻辑几乎完全一致,属于跨类复制粘贴。三处实现已出现细微不一致(如setSupport(true)调用位置在NfsPrimaryStorage中被放到分支判断之后,而其余两处在判断之前),说明重复代码正在逐步漂移,后续维护成本会持续增加。
plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java#L2674-L2698:抽取公共方法,仅保留该文件的调用。plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java#L1339-L1361:同上,抽取后调用公共方法(并在此基础上恢复虚拟化类型门禁的讨论见该文件单独评论)。plugin/sharedMountPointPrimaryStorage/src/main/java/org/zstack/storage/primary/smp/SMPPrimaryStorageBase.java#L393-L415:同上,抽取后调用公共方法。建议在
PrimaryStorageBase或某个共享工具类中新增一个静态方法,例如resolveSnapshotCapabilityByVolumeType(String volumeType),返回填充好 arrangement/placement/mode 的VolumeSnapshotCapability,三处调用方仅负责解析 volumeType 与是否setSupport。As per path instructions, "每个模块、类、方法应只承担单一的责任...重复代码(拷贝/粘贴、类似逻辑、抽象)"应被消除。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java` around lines 2674 - 2698, Extract the duplicated volume-type capability construction from AskVolumeSnapshotCapability handlers into one shared helper, such as resolveSnapshotCapabilityByVolumeType(String), returning a populated VolumeSnapshotCapability for Data, Root, and Memory and preserving unknown-type validation. Update plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java:2674-2698, plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java:1339-1361, and plugin/sharedMountPointPrimaryStorage/src/main/java/org/zstack/storage/primary/smp/SMPPrimaryStorageBase.java:393-415 so each handler only resolves volumeType, applies support status, and invokes the shared helper.Source: Path instructions
plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java (1)
3408-3408: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win将私有方法改为 lowerCamelCase。
Line 3408 和 Line 3427 的
BatchSyncVolumeResourceSizeOnPrimaryStorage以大写字母开头,不符合方法命名规范。建议修改
- .run(chain -> BatchSyncVolumeResourceSizeOnPrimaryStorage(msg, new NoErrorCompletion(chain) { + .run(chain -> batchSyncVolumeResourceSizeOnPrimaryStorage(msg, new NoErrorCompletion(chain) { - private void BatchSyncVolumeResourceSizeOnPrimaryStorage(BatchSyncVolumeResourceSizeOnPrimaryStorageMsg msg, NoErrorCompletion completion) { + private void batchSyncVolumeResourceSizeOnPrimaryStorage(BatchSyncVolumeResourceSizeOnPrimaryStorageMsg msg, NoErrorCompletion completion) {As per path instructions, “方法名、参数名、成员变量和局部变量:使用 lowerCamelCase 风格。”
Also applies to: 3427-3428
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java` at line 3408, 将私有方法 BatchSyncVolumeResourceSizeOnPrimaryStorage 重命名为 lowerCamelCase 的 batchSyncVolumeResourceSizeOnPrimaryStorage,并同步更新其在相关调用位置(包括两处调用)及方法声明,保持行为不变。Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@header/src/main/java/org/zstack/header/storage/primary/StorageResourceStats.java`:
- Around line 28-29: 将 StorageResourceStats.setSize 的参数类型从基本类型 long 改为包装类型
Long,使其与 size 字段及 setActualSize 保持一致;同时保留 batchStats 调用中 length 缺失时传递 null
的行为,避免自动拆箱触发 NullPointerException。
In `@storage/src/main/java/org/zstack/storage/volume/VolumeManagerImpl.java`:
- Around line 884-893: 更新 VolumeManagerImpl 中构造
BatchSyncVolumeResourceSizeOnPrimaryStorageMsg 的流程,保留 volume UUID 到 volumeType
的映射,并仅将对应 primary storage 明确支持 COW 的卷 UUID 传给 getSnapshotUuidInstallPaths;不要使用
syncSnapshotSize 这个聚合布尔值查询整批卷的快照路径,确保不同 volumeType 的快照不会被错误同步。
In
`@test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ScheduledVolumeSizeSyncCase.groovy`:
- Around line 405-408: 保存测试开始前的 AUTO_REFRESH_VOLUME_SCOPE 和刷新间隔原始值,并在
ScheduledVolumeSizeSyncCase 的 disableScheduledVolumeSizeSyncForTest
清理方法中恢复它们,替代固定写入 None/3600;在 ZbsPrimaryStorageCase 对应清理逻辑中复用相同的保存与恢复机制,避免写死清理值。
---
Nitpick comments:
In
`@plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java`:
- Line 3408: 将私有方法 BatchSyncVolumeResourceSizeOnPrimaryStorage 重命名为
lowerCamelCase 的
batchSyncVolumeResourceSizeOnPrimaryStorage,并同步更新其在相关调用位置(包括两处调用)及方法声明,保持行为不变。
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java`:
- Around line 2674-2698: Extract the duplicated volume-type capability
construction from AskVolumeSnapshotCapability handlers into one shared helper,
such as resolveSnapshotCapabilityByVolumeType(String), returning a populated
VolumeSnapshotCapability for Data, Root, and Memory and preserving unknown-type
validation. Update
plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java:2674-2698,
plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java:1339-1361,
and
plugin/sharedMountPointPrimaryStorage/src/main/java/org/zstack/storage/primary/smp/SMPPrimaryStorageBase.java:393-415
so each handler only resolves volumeType, applies support status, and invokes
the shared helper.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: eceacef4-c5d1-467c-8b2c-8b5402a254cd
📒 Files selected for processing (29)
header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageInventory.javaheader/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.javaheader/src/main/java/org/zstack/header/storage/primary/AskVolumeSnapshotCapabilityMsg.javaheader/src/main/java/org/zstack/header/storage/primary/PrimaryStorageInventory.javaheader/src/main/java/org/zstack/header/storage/primary/StorageResourceStats.javaheader/src/main/java/org/zstack/header/storage/primary/VolumeSnapshotCapability.javaheader/src/main/java/org/zstack/header/storage/snapshot/VolumeSnapshotStats.javaheader/src/main/java/org/zstack/header/volume/BatchSyncActiveVolumeSizeOnHostReply.javaheader/src/main/java/org/zstack/header/volume/BatchSyncVolumeResourceSizeOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/volume/BatchSyncVolumeResourceSizeOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/volume/BatchSyncVolumeSizeOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/volume/VolumeStats.javaplugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.javaplugin/expon/src/main/java/org/zstack/expon/ExponStorageController.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.javaplugin/sharedMountPointPrimaryStorage/src/main/java/org/zstack/storage/primary/smp/SMPPrimaryStorageBase.javaplugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.javaplugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.javasimulator/simulatorImpl/src/main/java/org/zstack/simulator/storage/primary/SimulatorPrimaryStorage.javastorage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.javastorage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.javastorage/src/main/java/org/zstack/storage/volume/VolumeManagerImpl.javatest/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ScheduledVolumeSizeSyncCase.groovytest/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy
💤 Files with no reviewable changes (1)
- header/src/main/java/org/zstack/header/volume/BatchSyncVolumeSizeOnPrimaryStorageReply.java
| public void setSize(long size) { | ||
| this.size = size; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
setSize 参数类型与字段类型不一致,可能导致 NPE。
size 字段为 Long(包装类型),setActualSize 接受 Long,但 setSize 接受 long(基本类型)。在 ZbsStorageController.batchStats 中调用 s.setSize(v.getValue().get("length")) 时,若 Map 中不存在 "length" 键,get 返回 null,自动拆箱为 long 将抛出 NullPointerException。
🔧 建议修复:统一 setter 参数类型
- public void setSize(long size) {
+ public void setSize(Long size) {
this.size = size;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public void setSize(long size) { | |
| this.size = size; | |
| public void setSize(Long size) { | |
| this.size = size; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@header/src/main/java/org/zstack/header/storage/primary/StorageResourceStats.java`
around lines 28 - 29, 将 StorageResourceStats.setSize 的参数类型从基本类型 long 改为包装类型
Long,使其与 size 字段及 setActualSize 保持一致;同时保留 batchStats 调用中 length 缺失时传递 null
的行为,避免自动拆箱触发 NullPointerException。
| boolean syncSnapshotSize = isSnapshotSizeSyncRequired(primaryStorageTypes.get(primaryStorageUuid), | ||
| activeVolumeSizeSyncInfo.volumeTypes); | ||
| BatchSyncVolumeResourceSizeOnPrimaryStorageMsg bmsg = new BatchSyncVolumeResourceSizeOnPrimaryStorageMsg(); | ||
| bmsg.setHostUuid(msg.getHostUuid()); | ||
| bmsg.setPrimaryStorageUuid(primaryStorageUuid); | ||
| bmsg.setVolumeUuidInstallPaths(activeVolumeSizeSyncInfo.volumeUuidInstallPaths); | ||
| bmsg.setWithSnapshot(syncSnapshotSize); | ||
| if (syncSnapshotSize) { | ||
| bmsg.setSnapshotUuidInstallPaths(getSnapshotUuidInstallPaths(primaryStorageUuid, | ||
| activeVolumeSizeSyncInfo.volumeUuidInstallPaths.keySet())); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
仅同步明确支持 COW 的卷类型对应的快照。
anyMatch 将 Root/Data 能力合并成一个布尔值,但随后 Line 892-893 会查询本批所有卷的快照路径。若主存仅对其中一种卷类型支持 COW,另一种类型的快照也会被发送和更新,失去了按 volumeType 查询能力的意义。
请保存 volume UUID 到类型的映射,并只向 getSnapshotUuidInstallPaths() 传入缓存值为 true 的卷 UUID,或按卷类型拆分请求。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@storage/src/main/java/org/zstack/storage/volume/VolumeManagerImpl.java`
around lines 884 - 893, 更新 VolumeManagerImpl 中构造
BatchSyncVolumeResourceSizeOnPrimaryStorageMsg 的流程,保留 volume UUID 到 volumeType
的映射,并仅将对应 primary storage 明确支持 COW 的卷 UUID 传给 getSnapshotUuidInstallPaths;不要使用
syncSnapshotSize 这个聚合布尔值查询整批卷的快照路径,确保不同 volumeType 的快照不会被错误同步。
| private void disableScheduledVolumeSizeSyncForTest() { | ||
| VolumeGlobalConfig.AUTO_REFRESH_VOLUME_SCOPE.updateValue("None") | ||
| updateRefreshVolumeSizeIntervalForTest("3600") | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
清理阶段应恢复原始全局配置。
两个测试都将进程级卷大小刷新配置固定改为 None/3600,会污染后续集成用例并造成顺序依赖。
test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ScheduledVolumeSizeSyncCase.groovy#L405-L408:保存测试前的两个配置值,并在清理阶段恢复。test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy#L1438-L1441:复用同样的保存与恢复机制,避免写死清理值。
📍 Affects 2 files
test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ScheduledVolumeSizeSyncCase.groovy#L405-L408(this comment)test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy#L1438-L1441
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ScheduledVolumeSizeSyncCase.groovy`
around lines 405 - 408, 保存测试开始前的 AUTO_REFRESH_VOLUME_SCOPE 和刷新间隔原始值,并在
ScheduledVolumeSizeSyncCase 的 disableScheduledVolumeSizeSyncForTest
清理方法中恢复它们,替代固定写入 None/3600;在 ZbsPrimaryStorageCase 对应清理逻辑中复用相同的保存与恢复机制,避免写死清理值。
ZBS COPY_ON_WRITE snapshot actual size is maintained by the storage backend and may change after snapshot creation. The console reads snapshot size from VolumeSnapshotVO, but the scheduled active-volume size sync refreshed only volume actual size before, so snapshot capacity could stay stale in the database.
During scheduled active-volume size sync, only primary storages whose snapshot mode is COPY_ON_WRITE attach snapshot install paths to the batch volume resource size sync request. The reply carries snapshot actual sizes so VolumeSnapshotVO.size can be refreshed together with volume actual size, without adding a manual snapshot size query flow for the console.
Rename BatchSyncVolumeSizeOnPrimaryStorageMsg to BatchSyncVolumeResourceSizeOnPrimaryStorageMsg because the scheduled batch sync now covers volume resources and, for COW snapshot backends, snapshot resources. Keep SyncVolumeSize and single-volume stats as volume-only flows.
Query snapshot capability by primary storage identity and volume type. PrimaryStorageInventory#getIdentity provides the cache identity: normal primary storages use type, and external primary storages override it with their identity, so VolumeManagerImpl does not depend on external storage VOs or external/non-external type checks.
Use StorageResourceStats as the batchStats return parent for VolumeStats and VolumeSnapshotStats. Batch stats accepts one installPaths collection; ZBS detects snapshot paths by @ and uses the volume-with-snapshot agent API only when COW snapshot size sync is required.
Test: git diff --cached --check
Test: mvn -pl header,storage -Dmaven.test.skip=true clean package
Resolves: ZSTAC-67903
Change-Id: I0f4c2b8e3a9d167f5c0e2b6a1d9c8e7f3456abcd
sync from gitlab !10571